/**
 * 
 */
package application;

import static implementations.Values.directedEdge;
import static implementations.Values.flowElem;
import static implementations.Values.flowGraph;
import static implementations.Values.vertex;
import static org.junit.Assert.assertEquals;
import interfaces.Edge;
import interfaces.FlowElem;
import interfaces.FlowGraph;
import interfaces.Vertex;

/**
 * @author Kai Bielenberg (kai.bielenberg@haw-hamburg.de)
 *
 */
public class GkaAufgabe3 {

    
    public static void main(String[] args) {
        
        System.out.println(":---------------------------------------------:");
        System.out.println(":Flussprobleme - Ford Fulkerson - Edmonds Karp:");
        System.out.println(":---------------------------------------------:");
        
        Vertex<String> source=vertex("source");
        Vertex<String> target=vertex("target");
        Vertex<String> v2=vertex("v2");
        Vertex<String> v3=vertex("v3");
        Vertex<String> v4=vertex("v4");
        Vertex<String> v5=vertex("v5");
        Edge<FlowElem, String> e1=directedEdge("e1",source, v2, flowElem(3,0));
        Edge<FlowElem, String> e2=directedEdge("e2",source, v4, flowElem(2,0));
        Edge<FlowElem, String> e3=directedEdge("e3",v2, v3, flowElem(2,0));
        Edge<FlowElem, String> e4=directedEdge("e4",v4, v2, flowElem(2,0));
        Edge<FlowElem, String> e5=directedEdge("e5",v3, v4, flowElem(1,0));
        Edge<FlowElem, String> e6=directedEdge("e6",v4, v5, flowElem(2,0));
        Edge<FlowElem, String> e7=directedEdge("e7",v5, v3, flowElem(1,0));
        Edge<FlowElem, String> e8=directedEdge("e8",v3, target, flowElem(2,0));
        Edge<FlowElem, String> e9=directedEdge("e9",v5, target, flowElem(4,0));
        FlowGraph<String> graph_folk_skript=flowGraph(source, target);
        graph_folk_skript.add(e1);
        graph_folk_skript.add(e2);
        graph_folk_skript.add(e3);
        graph_folk_skript.add(e4);
        graph_folk_skript.add(e5);
        graph_folk_skript.add(e6);
        graph_folk_skript.add(e7);
        graph_folk_skript.add(e8);
        graph_folk_skript.add(e9);
        

        System.out.println("Beispiel 1 Graph:\n");
        System.out.println(graph_folk_skript);
        System.out.println("---------------------------\n");
        System.out.println("Beispiel 1a: Graph aus dem Skript / Ford Fulkerson\n");
        System.out.println("Maximaler Fluss: " + graph_folk_skript.optimizeFordFulkerson());
        
        System.out.println("Laufzeit: " + graph_folk_skript.runtimeLastAlgorithm());
        System.out.println("Zugriffe: " + graph_folk_skript.lastNumberOfAccesses());
        
        System.out.println("Fluss fuer " +e1+": "+e1.element().flow());
        System.out.println("Fluss fuer " +e2+": "+e2.element().flow());
        System.out.println("Fluss fuer " +e3+": "+e3.element().flow());
        System.out.println("Fluss fuer " +e4+": "+e4.element().flow());
        System.out.println("Fluss fuer " +e5+": "+e5.element().flow());
        System.out.println("Fluss fuer " +e6+": "+e6.element().flow());
        System.out.println("Fluss fuer " +e7+": "+e7.element().flow());
        System.out.println("Fluss fuer " +e8+": "+e8.element().flow());
        System.out.println("Fluss fuer " +e9+": "+e9.element().flow());
        
        System.out.println("-------------------------------------------\n\n");
        
        
        Vertex<String> source2=vertex("source");
        Vertex<String> target2=vertex("target");
        Vertex<String> v2b=vertex("v2");
        Vertex<String> v3b=vertex("v3");
        Vertex<String> v4b=vertex("v4");
        Vertex<String> v5b=vertex("v5");
        Edge<FlowElem, String> e1b=directedEdge("e1",source2, v2b, flowElem(3,0));
        Edge<FlowElem, String> e2b=directedEdge("e2",source2, v4b, flowElem(2,0));
        Edge<FlowElem, String> e3b=directedEdge("e3",v2b, v3b, flowElem(2,0));
        Edge<FlowElem, String> e4b=directedEdge("e4",v4b, v2b, flowElem(2,0));
        Edge<FlowElem, String> e5b=directedEdge("e5",v3b, v4b, flowElem(1,0));
        Edge<FlowElem, String> e6b=directedEdge("e6",v4b, v5b, flowElem(2,0));
        Edge<FlowElem, String> e7b=directedEdge("e7",v5b, v3b, flowElem(1,0));
        Edge<FlowElem, String> e8b=directedEdge("e8",v3b, target2, flowElem(2,0));
        Edge<FlowElem, String> e9b=directedEdge("e9",v5b, target2, flowElem(4,0));
        FlowGraph<String> graph_edmonds_skript=flowGraph(source2, target2);
        graph_edmonds_skript.add(e1b);
        graph_edmonds_skript.add(e2b);
        graph_edmonds_skript.add(e3b);
        graph_edmonds_skript.add(e4b);
        graph_edmonds_skript.add(e5b);
        graph_edmonds_skript.add(e6b);
        graph_edmonds_skript.add(e7b);
        graph_edmonds_skript.add(e8b);
        graph_edmonds_skript.add(e9b);
        System.out.println("Beispiel 1b: Graph aus dem Skript / Edmonds Karp\n");
        System.out.println("Maximaler Fluss: " + graph_edmonds_skript.optimizeFordFulkerson());
       
        System.out.println("Laufzeit: " + graph_edmonds_skript.runtimeLastAlgorithm());
        System.out.println("Zugriffe: " + graph_edmonds_skript.lastNumberOfAccesses());
        System.out.println("Fluss fuer " +e1b+": "+e1b.element().flow());
        System.out.println("Fluss fuer " +e2b+": "+e2b.element().flow());
        System.out.println("Fluss fuer " +e3b+": "+e3b.element().flow());
        System.out.println("Fluss fuer " +e4b+": "+e4b.element().flow());
        System.out.println("Fluss fuer " +e5b+": "+e5b.element().flow());
        System.out.println("Fluss fuer " +e6b+": "+e6b.element().flow());
        System.out.println("Fluss fuer " +e7b+": "+e7b.element().flow());
        System.out.println("Fluss fuer " +e8b+": "+e8b.element().flow());
        System.out.println("Fluss fuer " +e9b+": "+e9b.element().flow());
        
        System.out.println("-------------------------------------------\n\n");
        
        
        Vertex<String> source4=vertex("source");
        Vertex<String> target4=vertex("target");
        Vertex<String> b1=vertex("b");
        Vertex<String> c1=vertex("c");
        Vertex<String> d1=vertex("d");
        Vertex<String> e1a=vertex("e");
        Vertex<String> f1=vertex("f");
        Edge<FlowElem, String> e1d=directedEdge("s_b",source4, b1, flowElem(3,0));
        Edge<FlowElem, String> e2d=directedEdge("s_d",source4, d1, flowElem(3,0));
        Edge<FlowElem, String> e3d=directedEdge("c_s",c1, source4, flowElem(3,0));
        Edge<FlowElem, String> e4d=directedEdge("b_c",b1, c1, flowElem(4,0));
        Edge<FlowElem, String> e5d=directedEdge("c_d",c1, d1, flowElem(1,0));
        Edge<FlowElem, String> e6d=directedEdge("d_e",d1, e1a, flowElem(2,0));
        Edge<FlowElem, String> e7d=directedEdge("e_b",e1a, b1, flowElem(1,0));
        Edge<FlowElem, String> e8d=directedEdge("d_f",d1, f1, flowElem(6,0));
        Edge<FlowElem, String> e9d=directedEdge("f_t",f1, target4, flowElem(9,0));
        Edge<FlowElem, String> e10d=directedEdge("e_t",e1a, target4, flowElem(1,0));
        Edge<FlowElem, String> e11d=directedEdge("c_e",c1, e1a, flowElem(2,0));

       
        FlowGraph<String> graph_edmonds_wiki1=flowGraph(source4, target4);
        graph_edmonds_wiki1.add(e1d);
        graph_edmonds_wiki1.add(e2d);
        graph_edmonds_wiki1.add(e3d);
        graph_edmonds_wiki1.add(e4d);
        graph_edmonds_wiki1.add(e5d);
        graph_edmonds_wiki1.add(e6d);
        graph_edmonds_wiki1.add(e7d);
        graph_edmonds_wiki1.add(e8d);
        graph_edmonds_wiki1.add(e9d);
        graph_edmonds_wiki1.add(e10d);
        graph_edmonds_wiki1.add(e11d);
        
        System.out.println("\n\nBeispiel 2 Graph:\n");
        System.out.println(graph_edmonds_wiki1);
        
        System.out.println("Beispiel 2a: Graph aus WIKI / Ford Fulkerson\n");
        System.out.println("Maximaler Fluss: " + graph_edmonds_wiki1.optimizeFordFulkerson());
       
        System.out.println("Laufzeit: " + graph_edmonds_wiki1.runtimeLastAlgorithm());
        System.out.println("Zugriffe: " + graph_edmonds_wiki1.lastNumberOfAccesses());
        System.out.println("Fluss fuer " +e1d+": "+e1d.element().flow());
        System.out.println("Fluss fuer " +e2d+": "+e2d.element().flow());
        System.out.println("Fluss fuer " +e3d+": "+e3d.element().flow());
        System.out.println("Fluss fuer " +e4d+": "+e4d.element().flow());
        System.out.println("Fluss fuer " +e5d+": "+e5d.element().flow());
        System.out.println("Fluss fuer " +e6d+": "+e6d.element().flow());
        System.out.println("Fluss fuer " +e7d+": "+e7d.element().flow());
        System.out.println("Fluss fuer " +e8d+": "+e8d.element().flow());
        System.out.println("Fluss fuer " +e9d+": "+e9d.element().flow());
        System.out.println("Fluss fuer " +e10d+": "+e10d.element().flow());
        System.out.println("Fluss fuer " +e11d+": "+e11d.element().flow());
        
        System.out.println("-------------------------------------------\n\n");
        
        
        
        Vertex<String> source3=vertex("source");
        Vertex<String> target3=vertex("target");
        Vertex<String> b=vertex("b");
        Vertex<String> c=vertex("c");
        Vertex<String> d=vertex("d");
        Vertex<String> e=vertex("e");
        Vertex<String> f=vertex("f");
        Edge<FlowElem, String> e1c=directedEdge("s_b",source3, b, flowElem(3,0));
        Edge<FlowElem, String> e2c=directedEdge("s_d",source3, d, flowElem(3,0));
        Edge<FlowElem, String> e3c=directedEdge("c_s",c, source3, flowElem(3,0));
        Edge<FlowElem, String> e4c=directedEdge("b_c",b, c, flowElem(4,0));
        Edge<FlowElem, String> e5c=directedEdge("c_d",c, d, flowElem(1,0));
        Edge<FlowElem, String> e6c=directedEdge("d_e",d, e, flowElem(2,0));
        Edge<FlowElem, String> e7c=directedEdge("e_b",e, b, flowElem(1,0));
        Edge<FlowElem, String> e8c=directedEdge("d_f",d, f, flowElem(6,0));
        Edge<FlowElem, String> e9c=directedEdge("f_t",f, target3, flowElem(9,0));
        Edge<FlowElem, String> e10c=directedEdge("e_t",e, target3, flowElem(1,0));
        Edge<FlowElem, String> e11c=directedEdge("c_e",c, e, flowElem(2,0));

       
        FlowGraph<String> graph_folk_wiki=flowGraph(source3, target3);
        graph_folk_wiki.add(e1c);
        graph_folk_wiki.add(e2c);
        graph_folk_wiki.add(e3c);
        graph_folk_wiki.add(e4c);
        graph_folk_wiki.add(e5c);
        graph_folk_wiki.add(e6c);
        graph_folk_wiki.add(e7c);
        graph_folk_wiki.add(e8c);
        graph_folk_wiki.add(e9c);
        graph_folk_wiki.add(e10c);
        graph_folk_wiki.add(e11c);
        
        
        
        System.out.println("Beispiel 2b: Graph aus WIKI / Edmonds Karp\n");
        System.out.println("Maximaler Fluss: " + graph_folk_wiki.optimizeEdmondsKarp());
       
        System.out.println("Laufzeit: " + graph_folk_wiki.runtimeLastAlgorithm());
        System.out.println("Zugriffe: " + graph_folk_wiki.lastNumberOfAccesses());
        System.out.println("Fluss fuer " +e1c+": "+e1c.element().flow());
        System.out.println("Fluss fuer " +e2c+": "+e2c.element().flow());
        System.out.println("Fluss fuer " +e3c+": "+e3c.element().flow());
        System.out.println("Fluss fuer " +e4c+": "+e4c.element().flow());
        System.out.println("Fluss fuer " +e5c+": "+e5c.element().flow());
        System.out.println("Fluss fuer " +e6c+": "+e6c.element().flow());
        System.out.println("Fluss fuer " +e7c+": "+e7c.element().flow());
        System.out.println("Fluss fuer " +e8c+": "+e8c.element().flow());
        System.out.println("Fluss fuer " +e9c+": "+e9c.element().flow());
        System.out.println("Fluss fuer " +e10c+": "+e10c.element().flow());
        System.out.println("Fluss fuer " +e11c+": "+e11c.element().flow());
        System.out.println("-------------------------------------------\n\n");
    }
}
